package view

import "fmt"

/*
	ClassFile {
	 u4 magic;
	 u2 minor_version;
	 u2 major_version;
	 u2 constant_pool_count;
	 cp_info constant_pool[constant_pool_count-1];
	 u2 access_flags;
	 u2 this_class;
	 u2 super_class;
	 u2 interfaces_count;
	 u2 interfaces[interfaces_count];
	 u2 fields_count;
	 field_info fields[fields_count];
	 u2 methods_count;
	 method_info methods[methods_count];
	 u2 attributes_count;
	 attribute_info attributes[attributes_count];
	}
*/
type ClassFile struct {
	Magic        uint32           `json:"magic"`
	MinorVersion uint16           `json:"minorVersion"`
	MajorVersion uint16           `json:"majorVersion"`
	ConstantPool ConstantPoolInfo `json:"constantPool"`

	AccessFlags uint16 `json:"accessFlags"`

	ThisClassIndex  uint16
	SuperClassIndex uint16
	InterfacesIndex []uint16
	ThisClass       Constant
	SuperClass      Constant
	Interfaces      []Constant

	Fields     []MemberInfo    `json:"fields"`
	Methods    []MemberInfo    `json:"methods"`
	Attributes []AttributeInfo `json:"attributes"`
}

func Parse(classData []byte) (cf *ClassFile, err error) {
	defer func() {
		if r := recover(); r != nil {
			var ok bool
			err, ok := r.(error)
			if !ok {
				fmt.Println(err)
				err = fmt.Errorf("%v\n", r)
			}
		}
	}()
	cr := &ClassReader{classData, 0}
	cf = &ClassFile{}
	cf.read(cr)
	return
}

func (self *ClassFile) read(cr *ClassReader) {
	self.readMagic(cr)
	self.readVersion(cr)
	self.readConstantPool(cr)
	self.readAccessFlags(cr)
	self.readClassName(cr)
	self.readSuperClassName(cr)
	self.readInterfaces(cr)
	self.readFields(cr)
	self.readMethods(cr)
	self.readAttributes(cr)
}

func (self *ClassFile) readMagic(cr *ClassReader) {
	self.Magic = cr.readUInt32(cr.readUInt8s(4))
	if self.Magic != 0xCAFEBABE {
		panic("不是有效的java文件")
	}
}

func (self *ClassFile) readVersion(cr *ClassReader) {
	self.readMinorVersion(cr)
	self.readMajorVersion(cr)
	fmt.Println("class file minorVersion", self.MinorVersion, "majorVersion", self.MajorVersion)

}

func (self *ClassFile) readMajorVersion(cr *ClassReader) {
	self.MajorVersion = cr.readUInt16(cr.readUInt8s(2))
}

func (self *ClassFile) readMinorVersion(cr *ClassReader) {
	self.MinorVersion = cr.readUInt16(cr.readUInt8s(2))
}

func (self *ClassFile) readConstantPool(cr *ClassReader) {
	self.ConstantPool = ReadConstantPool(cr)
}

func (self *ClassFile) readAccessFlags(cr *ClassReader) {
	self.AccessFlags = cr.readUInt16(cr.readUInt8s(2))
}

func (self *ClassFile) readFields(cr *ClassReader) {
	self.Fields = ReadMemberInfo(cr, self.ConstantPool)
}

func (self *ClassFile) readMethods(cr *ClassReader) {
	self.Methods = ReadMemberInfo(cr, self.ConstantPool)
}

func (self *ClassFile) readClassName(cr *ClassReader) {
	self.ThisClassIndex = cr.readUInt16(cr.readUInt8s(2))
	self.ThisClass = self.ConstantPool.ConstantList[self.ThisClassIndex-1]
}

func (self *ClassFile) readSuperClassName(cr *ClassReader) {
	self.SuperClassIndex = cr.readUInt16(cr.readUInt8s(2))
	self.SuperClass = self.ConstantPool.ConstantList[self.SuperClassIndex-1]
}
func (self *ClassFile) readInterfaces(cr *ClassReader) {
	size := cr.readUInt16(cr.readUInt8s(2))
	if size > 0 {
		self.InterfacesIndex = make([]uint16, size)
		self.Interfaces = make([]Constant, size)
		for i := 0; i < int(size); i++ {
			self.InterfacesIndex[i] = cr.readUInt16(cr.readUInt8s(2))
			self.Interfaces[i] = self.ConstantPool.ConstantList[self.InterfacesIndex[i]-1]
		}
	}
}
func (self *ClassFile) readAttributes(cr *ClassReader) {
	self.Attributes = make([]AttributeInfo, cr.readUInt16(cr.readUInt8s(2)))
	for i := 0; i < len(self.Attributes); i++ {
		self.Attributes[i] = NewAttributeInfo(cr, self.ConstantPool)
	}
}
